require_relative 'adapter/rype_adapter'

module Fabriq
  module Adapter
    extend self

    attr_accessor :adapter, :proxy, :rooms
    attr_accessor :skype_proxy_class

    def skype_proxy_class
      @skype_proxy_class || Fabriq::SkypeProxy
    end

    def load
      @adapter = Fabriq::Config.adapter.new
    end

    def run(&block)
      init_skype_proxy
      self.adapter.attach
      find_available_rooms do |rooms|
        @rooms = rooms
        block.call if block_given?
      end
      self.adapter.wait
    end

    def init_skype_proxy
      self.proxy = skype_proxy_class.new(self)
      self.proxy.start
    end

    def find_skype_room_by_id(room_id)
      @rooms.each do |room|
        return room if room.id == room_id
      end
      nil
    end

    def enqueue_outgoing_message(message)
      self.proxy.outgoing_messages << message
    end

    def subscribe_to_incoming_messages(&block)
      self.proxy.on_incoming_message(&block)
    end

    def message_received(&block)
      self.adapter.message_received do |raw_message|
        skype_room = find_skype_room_by_id(raw_message[:room_id])
        block.call(build_skype_message(skype_room, raw_message)) if block_given?
      end
    end

    def send_message(message)
      self.adapter.send_message(message.room.raw, message.body)
    end


    private

    def find_available_rooms(&block)
      self.adapter.available_rooms do |available_rooms|
        recursively_load_rooms(available_rooms) do |rooms|
          yield rooms
        end
      end
    end

    def recursively_load_rooms(rooms, loaded_rooms = [], &block)
      if rooms.length == 0
        yield loaded_rooms
      else
        adapter_room = rooms.shift
        self.adapter.load_room_information(adapter_room) do |loaded_room|
          loaded_rooms << build_skype_room(loaded_room)
          recursively_load_rooms(rooms, loaded_rooms, &block)
        end
      end
    end

    def build_skype_room(raw_room_information)
      Fabriq::Skype::Room.new(self, raw_room_information[:id], raw_room_information[:members], raw_room_information[:raw]).tap do |room|
        room.topic = raw_room_information[:topic]
      end
    end

    def build_skype_message(skype_room, raw_message_information)
      Fabriq::Skype::Message.new(skype_room, raw_message_information[:body]).tap do |message|
        message.from_name = raw_message_information[:from_name]
      end
    end

  end
end